package com.hundsun.yr.universal.library.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Vibrator;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.hundsun.yr.universal.library.R;
import com.hundsun.yr.universal.library.common.DensityUtils;
import com.hundsun.yr.universal.library.common.MD5Utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;


/**
 * 手势密码控件
 * @author tonglj
 *
 */
public class GestureLockView extends View {
	String TAG = "GestureLockView";
	private Context mContext;

	private boolean isContinue = true;// 是否继续
	private boolean result;// 结果是否正确
	private String key;// 结果
	private Timer timer;// 定时器
	private int eventX, eventY;
	private List<Integer> numLine = new ArrayList<Integer>();// 秘钥

	private Paint paintNormal;// 正常/错误画圈
	private Paint paintInTouch;// 按下
	private Paint paintLine;// 直线
	private Paint paintInnerCircle;// 圈内点
//	private Paint paintInnerCircleII;//第二圈
	private Path path = new Path();// 绘制的路径（连线）
	private Circle[] circles;
	private Circle[] tipCircles;
	
	private Vibrator vibrator;//震动
	private long[] partten = {50,50};// 停止 开启 停止 开启    

	private int OUT_CYCLE_NORMAL = Color.rgb(160, 162, 185); // 正常外圆颜色
	private int OUT_CYCLE_ONTOUCH = Color.rgb(255, 0, 0); // 选中外圆颜色
	private int INNER_CYCLE = Color.TRANSPARENT; // 选中内圆颜色
	private int INNER_INNER_CYCLE= Color.TRANSPARENT; // 选中最内圆颜色
	private int INNER_CYCLE_ONREMOVE = Color.TRANSPARENT; // 选择内圆颜色
//	private int LINE_COLOR = Color.argb(127, 006, 112, 154); // 连接线颜色
	private int LINE_COLOR = Color.rgb(255, 0, 0); // 连接线颜色
	
	private boolean showError = false;

	private String tips;
	private int tipHeight;
	private int adjustCount = 0;
	private String keyset;	//设置手势密码时用于存储第一次的手势密码
	private boolean isSetted = false;	//是否成功设置过一次密码
	private boolean errControl = true;	//是否控制两次密码不一致最大错误次数
	private Paint tipPaint;
	
	//对应String.xml
	private static final int ssmm_before=0; 
	private static final int ssmm_paining=1; 
	private static final int ssmm_relase_success=2; 
	private static final int ssmm_again=3; 
	private static final int ssmm_relase_err_minpwd=4; 
	private static final int ssmm_relase_err_unlikeness=5; 
	private int tipCount = ssmm_before;
	private static final int NORMAL = 0;
	private static final int SETTING = 1;
	
	
//	属性设置
	private int gesLockType = NORMAL;	//0 normal：不带小地图；1setting： 带小地图
	private String errormsg = "密码错误";
	private int minpwd = 0;	//最小连接点个数
	private int maxerr = 0;	//两次密码不一致最大错误次数
	private int timeout = 500;	//自动切换时间设置，不设置，默认为0.5秒
	private boolean showMaxError = false;	
	


	private float fontSize = 14;
	private OnCompleteListener mCompleteListener;
	private OnResetListener mResetListener;
	
	private Handler handler = new Handler();
	
	
	public GestureLockView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		init(context, attrs);
	}
	
	public GestureLockView(Context context) {
		this(context,null);
	}

	public Integer getGesLockType() {
		return gesLockType;
	}

	public void setGesLockType(int gesLockType) {
		this.gesLockType = gesLockType;
	}

	public int getMinpwd() {
		return minpwd;
	}

	public void setMinpwd(int minpwd) {
		this.minpwd = minpwd;
	}

	public int getMaxerr() {
		return maxerr;
	}

	public void setMaxerr(int maxerr) {
		this.maxerr = maxerr;
	}
	

	
	/***
	 * 设置密码错误
	 * @param errormsg 
	 */
	public void setPassError(String errormsg) {
		this.errormsg = errormsg;
		vibrator.vibrate(500);
	}

	public void setKey(String key) {
		this.key = key;
	}
	
	/**
	 * 初始化画笔
	 */
	@SuppressLint("Recycle") 
	private void init(Context context, AttributeSet attrs) {
		if(attrs != null){
			TypedArray  typearr = context.obtainStyledAttributes(attrs, R.styleable.GestureLockView);
			LINE_COLOR = typearr.getColor(R.styleable.GestureLockView_line_color,LINE_COLOR);
			OUT_CYCLE_NORMAL = typearr.getColor(R.styleable.GestureLockView_out_cycle_normal,OUT_CYCLE_NORMAL);
			OUT_CYCLE_ONTOUCH = typearr.getColor(R.styleable.GestureLockView_out_cycle_ontouch,OUT_CYCLE_ONTOUCH);
			INNER_CYCLE_ONREMOVE = typearr.getColor(R.styleable.GestureLockView_inner_cycle_onremove,INNER_CYCLE_ONREMOVE);
			minpwd = typearr.getInt(R.styleable.GestureLockView_minpwd,minpwd);
			maxerr = typearr.getInt(R.styleable.GestureLockView_maxerr,maxerr);
			if(maxerr>0){
				showMaxError = true;
			}
			gesLockType = typearr.getInt(R.styleable.GestureLockView_gesLockType,0);
			if(typearr.hasValue(R.styleable.GestureLockView_errormsg)){
				errormsg = typearr.getString(R.styleable.GestureLockView_errormsg);
			}
			INNER_CYCLE = typearr.getColor(R.styleable.GestureLockView_inner_cycle,INNER_CYCLE);
			INNER_INNER_CYCLE = typearr.getColor(R.styleable.GestureLockView_inner_inner_cycle,INNER_INNER_CYCLE);
		}
	
		
		paintNormal = new Paint();
		paintNormal.setAntiAlias(true);
		paintNormal.setStrokeWidth(DensityUtils.dp2px(mContext, 2));
		paintNormal.setStyle(Paint.Style.STROKE);

		paintInTouch = new Paint();
		paintInTouch.setAntiAlias(true);
		paintInTouch.setStrokeWidth(DensityUtils.dp2px(mContext, 2));
		paintInTouch.setStyle(Paint.Style.STROKE);

		paintLine = new Paint();
		paintLine.setAntiAlias(true);
		paintLine.setStrokeWidth(DensityUtils.dp2px(mContext, 4));
		paintLine.setStyle(Paint.Style.STROKE);

		paintInnerCircle = new Paint();
		paintInnerCircle.setAntiAlias(true);
		paintInnerCircle.setStrokeWidth(3);
		paintInnerCircle.setStyle(Paint.Style.FILL);
		
//		paintInnerCircleII = new Paint();
//		paintInnerCircleII.setAntiAlias(true);
//		paintInnerCircleII.setStrokeWidth(9);
//		paintInnerCircleII.setStyle(Paint.Style.FILL);
		
		tipPaint = new Paint();
		tipPaint.setAntiAlias(true);
//		tipPaint_grey.setStrokeWidth(9);
		tipPaint.setStyle(Paint.Style.FILL);
		
		vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
		if(maxerr<=0) {
			errControl = false;
		}
	}
	
	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);

		int perSize = 0;
		if (circles == null && (perSize = getWidth() / 6) > 0) {
			circles = new Circle[9];
			for (int i = 0; i < 3; i++) {
				for (int j = 0; j < 3; j++) {
					Circle myCircle = new Circle();
					// 取单数
					myCircle.setOx(perSize * (2 * j + 1));
					if(SETTING == gesLockType){
						myCircle.setOy(perSize * (2 * i + 1));
					}else{
						myCircle.setOy(perSize * (2 * i + 1)+DensityUtils.dp2px(mContext, 16));
					}
					// 放入整数
					myCircle.setNum(3 * i + j);
					// 设置半径
					myCircle.setR(perSize * 0.6f);
//					myCircle.setR(perSize * 0.67f);
					circles[3 * i + j] = myCircle;
				}
			}
		}
		
		if (tipCircles == null && (perSize = getWidth() / 6 / 2 / 6 * 3 / 2) > 0) {	// *3/2为适应性调整
			tipCircles = new Circle[9];
			for (int i = 0; i < 3; i++) {
				for (int j = 0; j < 3; j++) {
					Circle myCircle = new Circle();
					myCircle.setOx(getWidth()/2 - perSize * (2 * (2-j) - 2));
					myCircle.setOy(perSize * (2 * i +1));
					myCircle.setNum(3 * i + j);
					myCircle.setR(perSize * 0.6f);
					tipCircles[3 * i + j] = myCircle;
				}
			}
		}

	}
	
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		drawLines(canvas);	
		drawText(canvas);
		
		if(SETTING== gesLockType) {
			for (int i = 0; i < tipCircles.length; i++) {
				if(tipCircles[i].isInTouch()) {
					tipPaint.setColor(Color.rgb(0x33, 0x9e, 0xe2));
				}else {
					tipPaint.setColor(Color.rgb(0x99, 0x99, 0x99));
				}
//				canvas.drawCircle(tipCircles[i].getOx(), tipCircles[i].getOy(), tipCircles[i].getR(), tipPaint);
			}
		}
		
		for (int i = 0; i < circles.length; i++) {
	
			if (isContinue) {//抬手前
				if (circles[i].isInTouch()) {
					paintInTouch.setColor(OUT_CYCLE_ONTOUCH);
					paintLine.setColor(LINE_COLOR);
//					paintInnerCircle.setColor(INNER_CYCLE_ONTOUCH);
					paintInnerCircle.setColor(INNER_INNER_CYCLE);
//					paintInnerCircleII.setColor(INNER_CYCLE);
				
				}
				//抬起手后
				else{
					paintNormal.setColor(OUT_CYCLE_NORMAL);
					paintLine.setColor(LINE_COLOR);
					paintInnerCircle.setColor(INNER_CYCLE_ONREMOVE);
					paintInTouch.setColor(OUT_CYCLE_ONTOUCH);
					
				}
			}
			
			if(adjustCount <= 0 && SETTING == gesLockType) {	//还未调整过
				circles[i].setOy(circles[i].getOy() + tipHeight * 3);
			}
			
			if (circles[i].isInTouch()) {
				//绘制外圈
				canvas.drawCircle(circles[i].getOx(), circles[i].getOy(), circles[i].getR(), paintInTouch);
				//绘制内圈II
//				canvas.drawCircle(circles[i].getOx(), circles[i].getOy(), circles[i].getR()*7/8, paintInnerCircleII);
				//绘制内圈
				canvas.drawCircle(circles[i].getOx(), circles[i].getOy(), circles[i].getR()/3, paintInnerCircle);
				Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fingerprint);
				int i1 = bitmap.getWidth() / 2;
				int i2 = bitmap.getHeight() / 2;
				canvas.drawBitmap(bitmap,circles[i].getOx() - i1, circles[i].getOy() - i2, new Paint());
			}else{
				canvas.drawCircle(circles[i].getOx(), circles[i].getOy(), circles[i].getR(), paintNormal);
			}
		}
		adjustCount++;
	}
	
	/**
	 * 绘制线条
	 * @param canvas
	 */
	public void drawLines(Canvas canvas){
		path.reset();
		if (numLine!=null&&numLine.size()>0) {
			for (int i = 0; i < numLine.size(); i++) {
				int index = numLine.get(i);
				float x = circles[index].getOx();
				float y = circles[index].getOy();
				if (i==0) {
					path.moveTo(x, y);
				}else{
					path.lineTo(x, y);
				}
			}
			if (isContinue) {
				path.lineTo(eventX, eventY);
			}else{
				path.lineTo(circles[numLine.get(numLine.size()-1)].getOx(), circles[numLine.get(numLine.size()-1)].getOy());
			}
		}
		canvas.drawPath(path, paintLine);
	}

	
	/**
	 * 提示文字
	 * @param canvas
	 */
	private void drawText(Canvas canvas) {
		if(SETTING == gesLockType) {	//手势密码设置时不显示错误信息
			drawTips(canvas);
		}else {
			Paint textP = new Paint();
			textP.setColor(Color.RED);
			textP.setTextSize( DensityUtils.sp2px(mContext,fontSize));
			if (fontSize != 0) {
				textP.setTextSize(DensityUtils.sp2px(mContext,fontSize));
			}
			if(showError&& minpwd != 0 && minpwd>(key.length() + 1)/2){
				String error = getResources().getString(R.string.ssmm_relase_err_minpwd,minpwd);
				float x = (this.getWidth() - textP.measureText(error)) / 2;
				Rect rect = new Rect();
				textP.getTextBounds(error, 0, 1, rect);
				float y = rect.height();
				if(tipCircles.length>0 && SETTING == gesLockType){
					y = y + tipCircles[tipCircles.length-1].oy + DensityUtils.dp2px(mContext, 8);
				}
				canvas.drawText(error, x, y, textP);
			}else if (showMaxError&&showError && maxerr>0) {
				String error = getResources().getString(R.string.ssmm_relase_maxerror_info,maxerr);
				float x = (this.getWidth() - textP.measureText(error)) / 2;
				Rect rect = new Rect();
				textP.getTextBounds(error, 0, 1, rect);
				float y = rect.height();
				if(tipCircles.length>0 && SETTING == gesLockType){
					y = y + tipCircles[tipCircles.length-1].oy + DensityUtils.dp2px(mContext, 8);
				}
				canvas.drawText(error, x, y, textP);
				
			}else if (showError&&errormsg != null && errormsg.length() > 0) {
				float x = (this.getWidth() - textP.measureText(errormsg)) / 2;
				Rect rect = new Rect();
				textP.getTextBounds(errormsg, 0, 1, rect);
				float y = rect.height();
				if(tipCircles.length>0 && SETTING == gesLockType){
					y = y + tipCircles[tipCircles.length-1].getOy() + DensityUtils.dp2px(mContext, 8);
				}
				canvas.drawText(errormsg, x, y, textP);
			}
			
		}
	}
	
	/**
	 * 设置手势密码时的提示语
	 * @param canvas
	 */
	private void drawTips(Canvas canvas) {
		Paint textP = new Paint();
		textP.setColor(Color.rgb(160, 162, 185));
		
		textP.setTextSize( DensityUtils.sp2px(mContext,fontSize));
		if (fontSize != 0) {
			textP.setTextSize( DensityUtils.sp2px(mContext,fontSize));
		}
		
		switch (tipCount) {
		case ssmm_before:
			tips = getResources().getString(R.string.ssmm_before);
			break;
		case ssmm_paining:
			tips = getResources().getString(R.string.ssmm_paining);
			break;
		case ssmm_relase_success:
			tips = getResources().getString(R.string.ssmm_relase_success);
			break;
		case ssmm_again:
			tips = getResources().getString(R.string.ssmm_again);
			break;
		case ssmm_relase_err_minpwd:
			tips = getResources().getString(R.string.ssmm_relase_err_minpwd,minpwd);
			textP.setColor(Color.RED);
			break;
		case ssmm_relase_err_unlikeness:
			tips = getResources().getString(R.string.ssmm_relase_err_unlikeness);
			textP.setColor(Color.RED);
			break;

		default:
			break;
		}
		
		float x = (this.getWidth() - textP.measureText(tips)) / 2;
		x = x < (getWidth() / 6 / 2 * 3 / 2)?0:x;	//根据tipCircles perSize得出
		Rect rect = new Rect();
		textP.getTextBounds(tips, 0, 1, rect);
		float y = rect.height()+DensityUtils.dp2px(mContext, 8);
		tipHeight = (int) y+tipCircles[0].getOy();
		canvas.drawText(tips, x, y * 2 + tipCircles[tipCircles.length-1].getOy(), textP);
		
		if(tipCount == ssmm_relase_err_unlikeness){
			vibrator.vibrate(500);
		}
		
	}
	
	
	@SuppressLint("ClickableViewAccessibility") @Override
	public boolean onTouchEvent(MotionEvent event) {
		if (isContinue) {
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
			case MotionEvent.ACTION_MOVE:
				eventX = (int) event.getX();
				eventY = (int) event.getY();
				for (int i = 0; i < circles.length; i++) {
					if (circles[i].isPointIn(eventX, eventY)) {
						tipCount = ssmm_paining;
						circles[i].setInTouch(true);
						if(!isSetted) {
							tipCircles[i].setInTouch(true);
						}
//						vibrator.vibrate(50);
						vibrator.vibrate(partten, -1);
						if (!numLine.contains(circles[i].getNum())) {
							numLine.add(circles[i].getNum());
					}
					}
				}
				break;

			case MotionEvent.ACTION_UP:
				if(numLine.size()<minpwd){
					
				}
				isContinue = false;
				StringBuffer sb = new StringBuffer();
				for (int i = 0; i < numLine.size(); i++) {
					sb.append((i == numLine.size()-1)?numLine.get(i):numLine.get(i)+"|");
				}
				
				key = sb.toString();
				result = TextUtils.isEmpty(keyset)||TextUtils.equals(MD5Utils.getMD5String(key), keyset);
				if(!result){
					paintInnerCircle.setColor(Color.TRANSPARENT);
					paintInTouch.setColor(Color.RED);
					paintLine.setColor(Color.RED);
				}
				onComplete();
				break;
			default:
				break;
			}
			invalidate();
		}

		return true;
	}
	
	/**
	 * 单位圆
	 *
	 */
	public class Circle {
		private int ox,oy;//中心点坐标
		private float r;//半径
		private boolean inTouch;//是否按上
		private int num;//圆圈数字
		
		public int getOx() {
			return ox;
		}
		public void setOx(int ox) {
			this.ox = ox;
		}
		public int getOy() {
			return oy;
		}
		public void setOy(int oy) {
			this.oy = oy;
		}
		public float getR() {
			return r;
		}
		public void setR(float r) {
			this.r = r;
		}
		public boolean isInTouch() {
			return inTouch;
		}
		public void setInTouch(boolean inTouch) {
			this.inTouch = inTouch;
		}
		public int getNum() {
			return num;
		}
		public void setNum(int num) {
			this.num = num;
		}
		//判断是否在范围内
		public boolean isPointIn(int x,int y){
			double distance = Math.sqrt((x-ox)*(x-ox)+(y-oy)*(y-oy));
			return distance<r;
		}
	}
	
	/**
	 * 提交密码
	 */
	public void onComplete(){
		//还原
		int repair_time;
		if(SETTING == gesLockType) {
			repair_time = timeout;
		}else {
			repair_time = 500;
		}
		if(TextUtils.isEmpty(key)){
			repair(repair_time);
			return;
		}else if (!TextUtils.isEmpty(key) && minpwd > (key.length() + 1)/2) {
			showError = true;
			tipCount = ssmm_relase_err_minpwd;
			//注释 by tonglj
//			if(gesLockType==SETTING)
//				for (int i = 0; i < tipCircles.length; i++) {
//					tipCircles[i].setInTouch(false);
//				}
			repair(repair_time);
			return;
		} else {
			showError = false;
		}
		if(SETTING == gesLockType){//设置手势密码
			if(!isSetted){	//还未输入第一次手势密码
				keyset = MD5Utils.getMD5String(key);
				tipCount = ssmm_relase_success;
				isSetted = true;
				mResetListener.callback();
				postInvalidate();
				handler.postDelayed(new Runnable() {
					
					@Override
					public void run() {
						tipCount = ssmm_again;
						postInvalidate();
					}
				}, repair_time);
			}else {
				key = MD5Utils.getMD5String(key);
				if(!key.equals(keyset)) {
					if(errControl && --maxerr <= 0) {	//达到错误最大次数，执行回调函数
						mCompleteListener.onError();
					}
					tipCount = ssmm_relase_err_unlikeness;
					showError = true;
					vibrator.vibrate(500);
				}else {
					mCompleteListener.onComplete(key);
				}
			}
		}else {
			key = MD5Utils.getMD5String(key);
			if(!key.equals(keyset)) {
				if(errControl && --maxerr <= 0) {	//达到错误最大次数，执行回调函数
					mCompleteListener.onError();
				}
				showError = true;
				tipCount = ssmm_relase_err_unlikeness;
			}else {
				mCompleteListener.onComplete(key);
			}
		}
		
		repair(repair_time);
	} 
	
	/**
	 * 还原
	 */
	private void repair(int repair_time) {
		timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				eventX = eventY = 0;
				for (int i = 0; i < circles.length; i++) {
					circles[i].setInTouch(false);
				}
				if (numLine != null) {
					numLine.clear();
				}
				path.reset();
				isContinue = true;
				postInvalidate();
			}
		}, repair_time);
	}
	
	public String getKey(){
		return key;
	}
	
	   /**
     * 设置监听
     *
     * @param mCompleteListener
     */
    public void setOnCompleteListener(OnCompleteListener mCompleteListener) {
        this.mCompleteListener = mCompleteListener;
    }
    /**
     * 设置重置监听
     *
     */
    public void setOnResetListener(OnResetListener mResetListener) {
    	this.mResetListener = mResetListener;
    }
	

	
    /**
     * 手势密码结果回调
     */
    public interface OnCompleteListener {
        /**
         * 提交结果
         */
        public void onComplete(String result);
        /**
         * 绘制错误上限
         */
        public void onError();
    }
    
    
    public interface OnResetListener{
    	public void callback();
    }
    /**
     * 设置手势密码时重置函数
     */
    public void reset(){
    	if(gesLockType == SETTING && isSetted){
    		isSetted = false;
    		keyset="";
    		key = "";
    		tipCount = ssmm_before;
    		for (int i = 0; i < tipCircles.length; i++) {
    			tipCircles[i].setInTouch(false);
			}
    		repair(0);
    	}
    }

    public void setKeySet(String keySet){
    	this.keyset = keySet;
    }




}
